#pragma once
#include <iostream>
#include <string>
#include "SR.h"
#include <queue>
#include <mutex>
#include <condition_variable>
#include "Log.h"
#include "Comm.h"

using namespace LogMudule;
queue<pair<Behavior, string>> cmd_queue; // 命令队列
mutex queue_mutex;                       // 队列互斥锁
condition_variable queue_cv;

// 初始化输入
bool paraseArgs(int argc, char *argv[], bool &isRL, std::string &uname, std::string &passwd)
{
    if (argc == 4 && std::string(argv[1]) == "+")
    {
        isRL = true;
        uname = argv[2];
        passwd = argv[3];
        return true;
    }
    else if (argc == 3)
    {
        isRL = false;
        uname = argv[1];
        passwd = argv[2];
        return true;
    }
    return false;
}
// 下载数据
void HandGets(const std::string &file_name)
{
    if (!file_name.empty())
    {

        std::string fname = file_name;
        int sockfd = Connnect();
        verify(sockfd);
        if (sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket error";
            Die(SOCKET_ERR);
        }
        string md5sum;
        get_file_md5(file_name, md5sum);
        Protocol pro;
        pro.be_ = Behavior::GETS;
        int code = getCode();
        size_t filesize = getFileSize(file_name);
        string newpath = path + fname + " " + std::to_string(code) + " " + std::to_string(filesize) + " " + (md5sum.empty() ? "0" : md5sum);

        // gets /test/1 code 0 md5sum
        pro.len_ = newpath.size();
        strncpy(pro.buf, newpath.c_str(), pro.len_);
        Send(sockfd, pro);
        Protocol proto = Recv(sockfd);
        string md5sum1 = proto.buf; // 接受对方文件的md5sum
        // 用来存入自己的md5sum
        cout << "md5sum1:" << md5sum1 << endl;
        ofstream file(file_name, ios::app);

        if (!file.is_open())
        {
            std::cerr << "open error" << endl;
            Die(SOCKET_ERR);
        }
        if (proto.be_ == Behavior::OK)
        {
            bool Isruning = true;
            while (Isruning)
            {
                Protocol prorev = Recv(sockfd);
                if (prorev.len_ < 4095)
                {
                    Isruning = false;
                }
                file.write(prorev.buf, prorev.len_);
            }
        }

        file.close();
        get_file_md5(file_name, md5sum);
        cout << "md5sum:" << md5sum << endl;
        if (md5sum1 == md5sum)
        {
            cout << "[下载完成]" << file_name << endl;
        }
        else
        {
            std::remove(file_name.c_str());
            cout << "[下载出错]" << endl;
        }

        close(sockfd);
    }
}

// 上传数据
void HandPuts(const std::string &file_path)
{
    if (!file_path.empty())
    {
        std::string fname = file_path.substr(0, file_path.find_first_of(' '));
        std::string md5sum;
        std::string fpath = file_path.substr(file_path.find_first_of(' ') + 1);
        fpath.erase(0, fpath.find_first_not_of(" "));
        get_file_md5(fpath, md5sum);
        cout << "fname: " << fname << endl;
        cout << "fpath: " << fpath << endl;

        int sockfd = Connnect();

        if (sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "sockfd error";
        }

        verify(sockfd);
        Protocol pro;
        pro.be_ = Behavior::PUTS;
        int code = getCode();
        // puts 1 md5sum /test code
        // puts /test/1 md5sum code
        fname += (" " + md5sum + " " + std::to_string(code));
        string newfname = path + fname;
        pro.len_ = newfname.size();
        strncpy(pro.buf, newfname.c_str(), newfname.size());
        Send(sockfd, pro);
        cout << fpath << endl;
        int fd = open(fpath.c_str(), O_RDONLY);
        if (fd < 0)
        {
            perror("open");
            return;
        }

        bool isRunning = true;
        while (isRunning)
        {
            bzero(&pro, sizeof(pro));
            pro.be_ = Behavior::TRANSFER;
            int n = ::read(fd, pro.buf, 4095);
            pro.len_ = n;
            // cout << pro.buf << endl;
            if (n < 4095)
            {
                isRunning = false;
            }

            SEND(sockfd, pro, 4 + 4 + pro.len_);
        }
        close(fd);
        cout << "[文件上传完成]" << endl;

        close(sockfd);
    }
}
// 解析命令参数
Protocol parseCommand(const std::string &cmd)
{

    struct Protocol pro{};
    std::istringstream iss(cmd);
    std::string op;
    iss >> op;
    if (op == "cd")
        pro.be_ = Behavior::CD;
    else if (op == "ls")
    {
        pro.be_ = Behavior::LS;
    }
    else if (op == "pwd")
        pro.be_ = Behavior::PWD;
    else if (op == "rm")
        pro.be_ = Behavior::REMOVE;
    else if (op == "mkdir")
        pro.be_ = Behavior::MKDIR;
    else if (op == "gets")
    {
        pro.be_ = Behavior::GETS;
    }
    else if (op == "puts")
        pro.be_ = Behavior::PUTS;
    else if (op == "token")
        pro.be_ = Behavior::TOKEN;
    else
    {
        std::cerr << "[错误] 未知命令: " << op << std::endl;
    }
    std::string para;
    std::getline(iss, para);
    shared_ptr<vector<string>> param = parseCmd(para);
    bool isparase = CheckParase(op, param);
    if (isparase)
    {
        para.erase(0, para.find_first_not_of(" "));
        pro.len_ = para.size();
        strncpy(pro.buf, para.c_str(), pro.len_);
        pro.buf[sizeof(pro.buf) - 1] = '\0';
        return pro;
    }
    return pro;
}
// 解析用户输入的参数
void HandInput()
{
    vector<thread> works;
    for (int i = 0; i < 2; i++)
    {
        works.emplace_back([]()
                           {
            while(true)
            {
                pair<Behavior,string>task;
                {
                    unique_lock<mutex>lock(queue_mutex);
                    queue_cv.wait(lock,[](){return !cmd_queue.empty();});
                    task=cmd_queue.front();
                    cmd_queue.pop();
                }
                int sock = Connnect();
                verify(sock);
        if (sock < 0)
        {
            LOG(LogLevel::FATAL) << "sockfd error";
        }
        if(task.first==Behavior::GETS)
        {
            HandGets(task.second);
        }
        else if(task.first==Behavior::PUTS)
        {
            HandPuts(task.second);
        }
        //close(sock);
            } });
    }
    int sockfd = Connnect();
    verify(sockfd);
    Protocol init_pwd;
    init_pwd.be_ = Behavior::PWD;
    Send(sockfd, init_pwd);
    Protocol init_res = Recv(sockfd);
    path = init_res.buf;
    while (1)
    {
        cout << uname << ":" << path << "$";
        std::string cmd;
        std::getline(std::cin, cmd);
        if (cmd.empty())
            continue;
        std::istringstream iss(cmd);
        std::string op;
        iss >> op;
        if (op == "gets" || op == "puts")
        {
            std::string args;
            getline(iss, args);
            args.erase(0, args.find_first_not_of(" "));
            Behavior be = (op == "gets") ? Behavior::GETS : Behavior::PUTS;
            lock_guard<mutex> lock(queue_mutex);
            cmd_queue.emplace(be, args);
            queue_cv.notify_one();
            std::cout << "任务以入队列" << std::endl;
        }
        else if (IsComm(op))
        {

            if (sockfd < 0)
            {
                Die(SOCKET_ERR);
            }
            Protocol pro = parseCommand(cmd);
            if ((strlen(pro.buf) == 0) && (op != "ls" && op != "pwd"))
            {
                cerr << "错误:命令缺少必要的参数" << endl;
                continue;
            }
            Send(sockfd, pro);
            Protocol res = Recv(sockfd);
            if (cmd == "cd")
            {
                path = res.buf;
            }
            cout << res.buf << endl;

            if (pro.be_ == Behavior::CD)
            {
                // 获取更新后的路径
                Protocol pwd_pro;
                pwd_pro.be_ = Behavior::PWD;
                Send(sockfd, pwd_pro);
                Protocol pwd_res = Recv(sockfd);
                setCode(&res, pro.buf);
                path = pwd_res.buf;
            }
            else if (pro.be_ == Behavior::PWD)
            {
                path = res.buf;
            }

            // close(sockfd);
        }
        else
        {
            std::cerr << "[错误] 未知命令: " << op << std::endl;
            continue;
        }
    }
}
